<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="E7rOY" id="E7rOY"><span data-lake-id="u3d9cdf25" id="u3d9cdf25">典型回答</span></h1>
  <p data-lake-id="ubb180ffa" id="ubb180ffa"><br></p>
  <p data-lake-id="ud1b7042d" id="ud1b7042d"><span data-lake-id="u5e2ec714" id="u5e2ec714">我们所说的Redis单线程，指的是"其网络IO和键值对读写是由一个线程完成的"，也就是说，</span><strong><span data-lake-id="u9279b286" id="u9279b286">Redis中只有网络请求模块和数据操作模块是单线程的。而其他的如持久化存储模块、集群支撑模块等是多线程的。</span></strong></p>
  <p data-lake-id="u965e5b82" id="u965e5b82"><strong><span data-lake-id="u04ea8894" id="u04ea8894">​</span></strong><br></p>
  <p data-lake-id="u09e000c1" id="u09e000c1"><span data-lake-id="ua11b0767" id="ua11b0767">所以说，Redis中并不是没有多线程模型的，早在Redis 4.0的时候就已经针对部分命令做了多线程化。</span></p>
  <p data-lake-id="ue96966a9" id="ue96966a9"><span data-lake-id="u3f4c3af5" id="u3f4c3af5">​</span><br></p>
  <p data-lake-id="u0f84fdb5" id="u0f84fdb5"><span data-lake-id="ue3f4825a" id="ue3f4825a">一个计算机程序在执行的过程中，主要需要进行两种操作分别是读写操作和计算操作。</span></p>
  <p data-lake-id="u22d60836" id="u22d60836"><br></p>
  <p data-lake-id="uf196a829" id="uf196a829"><span data-lake-id="u09e1fd44" id="u09e1fd44">其中读写操作主要是涉及到的就是I/O操作，其中包括网络I/O和磁盘I/O。计算操作主要涉及到CPU。</span></p>
  <p data-lake-id="uaf43f9f1" id="uaf43f9f1"><br></p>
  <p data-lake-id="uc31de33f" id="uc31de33f"><strong><span data-lake-id="uae61752c" id="uae61752c">而多线程的目的，就是通过并发的方式来提升I/O的利用率和CPU的利用率。</span></strong></p>
  <p data-lake-id="ud790f537" id="ud790f537"><span data-lake-id="ueed5a21f" id="ueed5a21f">​</span><br></p>
  <p data-lake-id="u318365d6" id="u318365d6"><strong><span data-lake-id="u4fabe218" id="u4fabe218">之所以Redis没有用多线程处理IO操作，主要是因为，Redis的操作基本都是基于内存的，CPU资源根本就不是Redis的性能瓶颈。</span></strong></p>
  <h1 data-lake-id="Rqzy6" id="Rqzy6"><br></h1>
  <h1 data-lake-id="W4RXk" id="W4RXk"><span data-lake-id="u00596255" id="u00596255">扩展知识</span></h1>
  <h3 data-lake-id="575aed0d" id="575aed0d"><span data-lake-id="ue604b705" id="ue604b705">Redis为什么最开始被设计成单线程的？</span></h3>
  <p data-lake-id="ud61ae5ba" id="ud61ae5ba"><br></p>
  <p data-lake-id="u54980cbf" id="u54980cbf"><span data-lake-id="ud772cd5d" id="ud772cd5d">Redis作为一个成熟的分布式缓存框架，它由很多个模块组成，如网络请求模块、索引模块、存储模块、高可用集群支撑模块、数据操作模块等。</span></p>
  <p data-lake-id="u3044f969" id="u3044f969"><br></p>
  <p data-lake-id="ubbdc3de5" id="ubbdc3de5"><span data-lake-id="u39d3e7f0" id="u39d3e7f0">很多人说Redis是单线程的，就认为Redis中所有模块的操作都是单线程的，其实这是不对的。</span></p>
  <p data-lake-id="u52b0b923" id="u52b0b923"><br></p>
  <p data-lake-id="u23dc6bbe" id="u23dc6bbe"><span data-lake-id="udfc04e69" id="udfc04e69">我们所说的Redis单线程，指的是"其网络IO和键值对读写是由一个线程完成的"，也就是说，</span><strong><span data-lake-id="u3531a331" id="u3531a331">Redis中只有网络请求模块和数据操作模块是单线程的。而其他的如持久化存储模块、集群支撑模块等是多线程的。</span></strong></p>
  <p data-lake-id="u3777a928" id="u3777a928"><br></p>
  <p data-lake-id="u40622b51" id="u40622b51"><span data-lake-id="u5e7a4357" id="u5e7a4357">所以说，Redis中并不是没有多线程模型的，早在Redis 4.0的时候就已经针对部分命令做了多线程化。</span></p>
  <p data-lake-id="u6f121ed6" id="u6f121ed6"><br></p>
  <p data-lake-id="uac6556c2" id="uac6556c2"><span data-lake-id="u27599448" id="u27599448">那么，为什么网络操作模块和数据存储模块最初并没有使用多线程呢？</span></p>
  <p data-lake-id="u91b17fb3" id="u91b17fb3"><br></p>
  <p data-lake-id="u9dec3dd1" id="u9dec3dd1"><span data-lake-id="udf5f6039" id="udf5f6039">这个问题的答案比较简单！因为："没必要！"</span></p>
  <p data-lake-id="u1d9210e0" id="u1d9210e0"><br></p>
  <p data-lake-id="u64159711" id="u64159711"><span data-lake-id="u7677224e" id="u7677224e">为什么没必要呢？我们先来说一下，什么情况下要使用多线程？</span></p>
  <p data-lake-id="ub43b378e" id="ub43b378e"><br></p>
  <h4 data-lake-id="e4c5cf4e" id="e4c5cf4e"><span data-lake-id="u4655a277" id="u4655a277">多线程适用场景</span></h4>
  <p data-lake-id="uf3688a3e" id="uf3688a3e"><br></p>
  <p data-lake-id="uc7afe448" id="uc7afe448"><span data-lake-id="ufe92f2be" id="ufe92f2be">一个计算机程序在执行的过程中，主要需要进行两种操作分别是读写操作和计算操作。</span></p>
  <p data-lake-id="u4beccc85" id="u4beccc85"><br></p>
  <p data-lake-id="ucf856bdd" id="ucf856bdd"><span data-lake-id="u51a7b9ba" id="u51a7b9ba">其中读写操作主要是涉及到的就是I/O操作，其中包括网络I/O和磁盘I/O。计算操作主要涉及到CPU。</span></p>
  <p data-lake-id="ud6cde0e0" id="ud6cde0e0"><br></p>
  <p data-lake-id="u4699808a" id="u4699808a"><strong><span data-lake-id="u068c7a47" id="u068c7a47">而多线程的目的，就是通过并发的方式来提升I/O的利用率和CPU的利用率。</span></strong></p>
  <p data-lake-id="u69c902eb" id="u69c902eb"><br></p>
  <p data-lake-id="u04b24505" id="u04b24505"><span data-lake-id="ubd73a56b" id="ubd73a56b">那么，Redis需不需要通过多线程的方式来提升提升I/O的利用率和CPU的利用率呢？</span></p>
  <p data-lake-id="u26547e6d" id="u26547e6d"><br></p>
  <p data-lake-id="u892647e5" id="u892647e5"><span data-lake-id="u4041b825" id="u4041b825">首先，我们可以肯定的说，Redis不需要提升CPU利用率，因为</span><strong><span data-lake-id="ueeecf31e" id="ueeecf31e">Redis的操作基本都是基于内存的，CPU资源根本就不是Redis的性能瓶颈。</span></strong></p>
  <p data-lake-id="u0810b56c" id="u0810b56c"><br></p>
  <p data-lake-id="uca63b02a" id="uca63b02a"><strong><span data-lake-id="uae74ca2c" id="uae74ca2c">所以，通过多线程技术来提升Redis的CPU利用率这一点是完全没必要的。</span></strong></p>
  <p data-lake-id="u85c493f2" id="u85c493f2"><br></p>
  <p data-lake-id="u72cb90fa" id="u72cb90fa"><span data-lake-id="u1cf7dd05" id="u1cf7dd05">那么，使用多线程技术来提升Redis的I/O利用率呢？是不是有必要呢？</span></p>
  <p data-lake-id="u8cddf102" id="u8cddf102"><br></p>
  <p data-lake-id="u7b2f2de9" id="u7b2f2de9"><span data-lake-id="ue2714a21" id="ue2714a21">Redis确实是一个I/O操作密集的框架，他的数据操作过程中，会有大量的网络I/O和磁盘I/O的发生。要想提升Redis的性能，是一定要提升Redis的I/O利用率的，这一点毋庸置疑。</span></p>
  <p data-lake-id="u6c7ff7e6" id="u6c7ff7e6"><br></p>
  <p data-lake-id="u7871ee13" id="u7871ee13"><span data-lake-id="u77b77e47" id="u77b77e47">但是，</span><strong><span data-lake-id="u5e2c36a6" id="u5e2c36a6">提升I/O利用率，并不是只有采用多线程技术这一条路可以走！</span></strong></p>
  <p data-lake-id="u1872ebcd" id="u1872ebcd"><br></p>
  <h4 data-lake-id="10688b42" id="10688b42"><span data-lake-id="u7da31dc0" id="u7da31dc0">多线程的弊端</span></h4>
  <p data-lake-id="u92b2a287" id="u92b2a287"><br></p>
  <p data-lake-id="u2f772a47" id="u2f772a47"><span data-lake-id="uad55d9e2" id="uad55d9e2">我们在很多文章中介绍过一些Java中的多线程技术，如内存模型、锁、CAS等，这些都是Java中提供的一些在多线程情况下保证线程安全的技术。</span></p>
  <p data-lake-id="u916785d9" id="u916785d9"><br></p>
  <blockquote data-lake-id="u603d14c9" id="u603d14c9">
   <p data-lake-id="ua80d1a30" id="ua80d1a30"><span data-lake-id="u0e2dabdb" id="u0e2dabdb">线程安全：是编程中的术语，指某个函数、函数库在并发环境中被调用时，能够正确地处理多个线程之间的共享变量，使程序功能正确完成。</span></p>
  </blockquote>
  <p data-lake-id="ua858f964" id="ua858f964"><br></p>
  <p data-lake-id="u0c1de14b" id="u0c1de14b"><span data-lake-id="ubc1d8879" id="ubc1d8879">和Java类似，所有支持多线程的编程语言或者框架，都不得不面对的一个问题，那就是如何解决多线程编程模式带来的共享资源的并发控制问题。</span></p>
  <p data-lake-id="u2c79fb25" id="u2c79fb25"><br></p>
  <p data-lake-id="u7c48e088" id="u7c48e088"><strong><span data-lake-id="u2ab6a9ae" id="u2ab6a9ae">虽然，采用多线程可以帮助我们提升CPU和I/O的利用率，但是多线程带来的并发问题也给这些语言和框架带来了更多的复杂性。而且，多线程模型中，多个线程的互相切换也会带来一定的性能开销。</span></strong></p>
  <p data-lake-id="u90301484" id="u90301484"><br></p>
  <p data-lake-id="ufbe4fbbf" id="ufbe4fbbf"><span data-lake-id="u62bb841b" id="u62bb841b">所以，在提升I/O利用率这个方面上，Redis并没有采用多线程技术，而是选择了</span><strong><span data-lake-id="ucdf44e2e" id="ucdf44e2e">多路复用 I/O</span></strong><span data-lake-id="uf72839c9" id="uf72839c9">技术。</span></p>
  <p data-lake-id="ub0578852" id="ub0578852"><br></p>
  <h4 data-lake-id="5db9fd7c" id="5db9fd7c"><span data-lake-id="uc9eddf14" id="uc9eddf14">小结</span></h4>
  <p data-lake-id="u46476485" id="u46476485"><br></p>
  <p data-lake-id="u65ceb44e" id="u65ceb44e"><span data-lake-id="ue8b348cb" id="ue8b348cb">Redis并没有在网络请求模块和数据操作模块中使用多线程模型，主要是基于以下四个原因：</span></p>
  <p data-lake-id="uf18eecde" id="uf18eecde"><br></p>
  <ul list="uc103d02e">
   <li fid="udb11a44a" data-lake-id="u1839b618" id="u1839b618"><span data-lake-id="u6bfcc121" id="u6bfcc121">1、Redis 操作基于内存，绝大多数操作的性能瓶颈不在 CPU</span></li>
   <li fid="udb11a44a" data-lake-id="u552fd775" id="u552fd775"><span data-lake-id="u68263d83" id="u68263d83">2、使用单线程模型，可维护性更高，开发，调试和维护的成本更低</span></li>
   <li fid="udb11a44a" data-lake-id="ub288b234" id="ub288b234"><span data-lake-id="u6a79d3d9" id="u6a79d3d9">3、单线程模型，避免了线程间切换带来的性能开销</span></li>
   <li fid="udb11a44a" data-lake-id="u4a889f15" id="u4a889f15"><span data-lake-id="ud77b96c8" id="ud77b96c8">4、在单线程中使用多路复用 I/O技术也能提升Redis的I/O利用率</span></li>
  </ul>
  <p data-lake-id="ufdbc1730" id="ufdbc1730"><br></p>
  <p data-lake-id="u3b5e6c2c" id="u3b5e6c2c"><span data-lake-id="u29ecd4d5" id="u29ecd4d5">还是要记住：Redis并不是完全单线程的，只是有关键的键值对读写是由一个线程完成的。</span></p>
  <p data-lake-id="u397dd818" id="u397dd818"><br></p>
  <h3 data-lake-id="e1da6236" id="e1da6236"><span data-lake-id="uea5dfb5b" id="uea5dfb5b">Redis的多路复用</span></h3>
  <p data-lake-id="u2bf7fa26" id="u2bf7fa26"><br></p>
  <p data-lake-id="uf151cb5f" id="uf151cb5f"><span data-lake-id="u12182c07" id="u12182c07"> </span></p>
  <h3 data-lake-id="9da35ac4" id="9da35ac4"><span data-lake-id="u868d3bc5" id="u868d3bc5">为什么Redis 6.0 引入多线程</span></h3>
  <p data-lake-id="ueb68c28d" id="ueb68c28d"><br></p>
 </body>
</html>